Alternative sync#1123
Conversation
|
| return Ok(new List<DataIssueDisplayModelDto> | ||
| { | ||
| new() | ||
| { | ||
| IssueType = "System Error", | ||
| Description = $"Failed to analyze data issues: {ex.Message}", | ||
| Date = DateTime.Now, | ||
| AccountName = "System", | ||
| ActivityType = "Error", | ||
| TransactionId = "ERROR", | ||
| ActivityDescription = ex.ToString(), | ||
| Severity = "Error" | ||
| } | ||
| }); |
Development container publishedInstall with: |
There was a problem hiding this comment.
Pull request overview
This PR introduces an “alternative sync” data path for the PortfolioViewer by allowing the Blazor WASM client to switch between reading from the locally synced database and querying the API service directly. It adds API-backed service implementations, proxy services that route to the active data source, and new API endpoints to serve holdings/accounts/transactions/data-issues/upcoming-dividends.
Changes:
- Added
IDataSourceService+ keyed-DI proxies inPortfolioViewer.WASMto dynamically route between local DB services and API-backed services. - Implemented API-backed
*Serviceclasses inPortfolioViewer.WASM.Datathat call newPortfolioViewer.ApiServiceREST controllers. - Added unit tests for the new proxy routing and API-backed service HTTP mapping; added basic ApiService controller smoke tests and EF InMemory dependency.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| PortfolioViewer/PortfolioViewer.WASM/Services/UpcomingDividendsServiceProxy.cs | Proxy routes upcoming dividends calls to local vs API service. |
| PortfolioViewer/PortfolioViewer.WASM/Services/TransactionServiceProxy.cs | Proxy routes transactions calls to local vs API service. |
| PortfolioViewer/PortfolioViewer.WASM/Services/IDataSourceService.cs | Adds a toggle service (UseApiDirectly) to control routing. |
| PortfolioViewer/PortfolioViewer.WASM/Services/HoldingsDataServiceProxy.cs | Proxy routes holdings calls to local vs API service. |
| PortfolioViewer/PortfolioViewer.WASM/Services/DataSourceKeys.cs | Defines keyed-DI keys for local vs API implementations. |
| PortfolioViewer/PortfolioViewer.WASM/Services/DataIssuesServiceProxy.cs | Proxy routes data-issues calls to local vs API service. |
| PortfolioViewer/PortfolioViewer.WASM/Services/AccountDataServiceProxy.cs | Proxy routes accounts calls to local vs API service. |
| PortfolioViewer/PortfolioViewer.WASM/Program.cs | Switches registrations to keyed DI + proxy routing; registers IDataSourceService. |
| PortfolioViewer/PortfolioViewer.WASM.UnitTests/Services/DataSourceProxyTests.cs | Tests proxy routing behavior for UseApiDirectly on/off. |
| PortfolioViewer/PortfolioViewer.WASM.Data/Services/ApiUpcomingDividendsService.cs | API-backed upcoming dividends client. |
| PortfolioViewer/PortfolioViewer.WASM.Data/Services/ApiTransactionService.cs | API-backed transactions client (paginated + types). |
| PortfolioViewer/PortfolioViewer.WASM.Data/Services/ApiServiceBase.cs | Shared JSON options (incl. DateOnly) for API clients. |
| PortfolioViewer/PortfolioViewer.WASM.Data/Services/ApiHoldingsDataService.cs | API-backed holdings client (incl. price/value history). |
| PortfolioViewer/PortfolioViewer.WASM.Data/Services/ApiDataIssuesService.cs | API-backed data issues client. |
| PortfolioViewer/PortfolioViewer.WASM.Data/Services/ApiAccountDataService.cs | API-backed accounts client (min-date, value history, tax report, etc.). |
| PortfolioViewer/PortfolioViewer.WASM.Data.UnitTests/Services/ApiTransactionServiceTests.cs | Tests HTTP mapping/null handling for transactions API client. |
| PortfolioViewer/PortfolioViewer.WASM.Data.UnitTests/Services/ApiHoldingsDataServiceTests.cs | Tests holdings API client endpoints and DateOnly mapping. |
| PortfolioViewer/PortfolioViewer.WASM.Data.UnitTests/Services/ApiDataIssuesAndDividendsServiceTests.cs | Tests data-issues + upcoming-dividends API clients. |
| PortfolioViewer/PortfolioViewer.WASM.Data.UnitTests/Services/ApiAccountDataServiceTests.cs | Tests accounts API client behavior. |
| PortfolioViewer/PortfolioViewer.ApiService/Controllers/UpcomingDividendsController.cs | Adds REST endpoint for upcoming dividends sourced from DB. |
| PortfolioViewer/PortfolioViewer.ApiService/Controllers/TransactionsController.cs | Adds REST endpoints for paginated transactions + transaction types. |
| PortfolioViewer/PortfolioViewer.ApiService/Controllers/HoldingsController.cs | Adds REST endpoints for holdings, holding detail, and history series. |
| PortfolioViewer/PortfolioViewer.ApiService/Controllers/DataIssuesController.cs | Adds REST endpoint for activities without holdings. |
| PortfolioViewer/PortfolioViewer.ApiService/Controllers/AccountsController.cs | Adds REST endpoints for accounts, min-date, symbol profiles, value history, and tax report. |
| PortfolioViewer/PortfolioViewer.ApiService.UnitTests/PortfolioViewer.ApiService.UnitTests.csproj | Adds EFCore InMemory provider for controller tests. |
| PortfolioViewer/PortfolioViewer.ApiService.UnitTests/Controllers/TransactionsControllerTests.cs | Adds basic controller smoke test(s). |
| PortfolioViewer/PortfolioViewer.ApiService.UnitTests/Controllers/DataIssuesAndDividendsControllerTests.cs | Adds basic controller smoke test(s) for data issues/dividends. |
| PortfolioViewer/PortfolioViewer.ApiService.UnitTests/Controllers/AccountsControllerTests.cs | Adds basic controller smoke test(s) for accounts. |
| IQueryable<Activity> query = db.Activities | ||
| .Include(a => a.Account) | ||
| .Include(a => a.Holding) | ||
| .Where(a => a.Date >= p.StartDate.ToDateTime(TimeOnly.MinValue) && a.Date <= p.EndDate.ToDateTime(TimeOnly.MinValue)); |
| if (sortColumn == "TotalValue") | ||
| { | ||
| // Pattern matching not supported in EF expression trees – sort by a computed scalar helper. | ||
| // Fall through to default date sort to avoid an expression-tree exception. | ||
| return sortAscending ? query.OrderBy(a => a.Date) : query.OrderByDescending(a => a.Date); | ||
| } |
| catch (Exception ex) | ||
| { | ||
| return Ok(new List<DataIssueDisplayModelDto> | ||
| { | ||
| new() | ||
| { | ||
| IssueType = "System Error", | ||
| Description = $"Failed to analyze data issues: {ex.Message}", | ||
| Date = DateTime.Now, | ||
| AccountName = "System", | ||
| ActivityType = "Error", | ||
| TransactionId = "ERROR", | ||
| ActivityDescription = ex.ToString(), | ||
| Severity = "Error" | ||
| } | ||
| }); | ||
| } |
| Symbol = h.SymbolProfiles.Select(p => p.Symbol).FirstOrDefault(), | ||
| Name = h.SymbolProfiles.Select(p => p.Name).FirstOrDefault(), |
| var list = await db.Holdings | ||
| .Where(x => x.CalculatedSnapshots.Any(y => y.AccountId == accountId || accountId == null)) | ||
| .Select(x => new | ||
| { | ||
| Holding = x, | ||
| Snapshots = x.CalculatedSnapshots | ||
| .Where(s => s.AccountId == accountId || accountId == null) | ||
| .Where(s => s.Date == lastKnownDate) | ||
| }) | ||
| .OrderBy(x => x.Holding.Id) | ||
| .ToListAsync(cancellationToken); |
| var activitiesWithoutHoldings = await db.Activities | ||
| .Include(a => a.Account) | ||
| .Where(a => a.Holding == null) | ||
| .OrderByDescending(a => a.Date) | ||
| .ThenBy(a => a.Id) | ||
| .ToListAsync(cancellationToken); |




No description provided.